package org.ns.socket.client.handler;

import org.ns.socket.client.ByteBuffer;
import org.ns.socket.client.SocketContext;
import org.ns.socket.client.codec.SocketDecodeHandler;
import org.ns.socket.client.codec.SocketEncodeHandler;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;

public abstract class AbstractSocketHandler implements SocketHandler {

    public AbstractSocketHandler() {

    }


    private ExecutorService workerThread;
    private SocketDecodeHandler socketDecodeHandler;
    private SocketEncodeHandler socketEncodeHandler;
    private SocketReaderHandler socketReaderHandler;
    private SocketConfig socketConfig = new SocketConfig();

    private LinkedList<Object> outObject = new LinkedList<>();

    @Override
    public void setWorkerThread(ExecutorService workerThread) {
        this.workerThread = workerThread;
    }

    protected void execute(Runnable run) {
        if (workerThread != null) {
            workerThread.execute(run);
        } else {
            run.run();
        }
    }

    @Override
    public void setSocketDecodeHandler(SocketDecodeHandler socketDecodeHandler) {
        this.socketDecodeHandler = socketDecodeHandler;
    }

    @Override
    public void setSocketEncodeHandler(SocketEncodeHandler socketEncodeHandler) {
        this.socketEncodeHandler = socketEncodeHandler;
    }

    @Override
    public void setSocketReaderHandler(SocketReaderHandler socketReaderHandler) {
        this.socketReaderHandler = socketReaderHandler;
    }

    @Override
    public void setSocketConfig(SocketConfig socketConfig) {
        this.socketConfig = socketConfig;
    }

    public ExecutorService getWorkerThread() {
        return workerThread;
    }

    public SocketDecodeHandler getSocketDecodeHandler() {
        return socketDecodeHandler;
    }

    public SocketEncodeHandler getSocketEncodeHandler() {
        return socketEncodeHandler;
    }

    public SocketReaderHandler getSocketReaderHandler() {
        return socketReaderHandler;
    }

    public SocketConfig getSocketConfig() {
        return socketConfig;
    }


    protected void readHandler(ByteBuffer byteBuffer, SocketContext socketContext) {
        if (getSocketDecodeHandler() != null ) {
            getSocketDecodeHandler().decode(byteBuffer, outObject);
        } else {
            outObject.add(byteBuffer);
        }

        Iterator<Object> iterator = outObject.iterator();
        while (iterator.hasNext()) {
            Object o = iterator.next();
            iterator.remove();

            execute(()-> {
                getSocketReaderHandler().handler(socketContext, o);
            });
        }
    }

    protected byte[] writeHandler(Object msg) {
        if (getSocketEncodeHandler() == null) {
            if (msg instanceof byte[]) {
               return (byte[])msg;
            } else if (msg instanceof ByteBuffer) {
                return ((ByteBuffer) msg).toBytes();
            } else if (msg instanceof java.nio.ByteBuffer) {
                java.nio.ByteBuffer byteBuffer = (java.nio.ByteBuffer) msg;
                byteBuffer.flip();
                byte[] buf = new byte[byteBuffer.remaining()];
                byteBuffer.get(buf);
                return buf;
            }
            return null;
        }

        ByteBuffer byteBuffer = new ByteBuffer(10240);
        getSocketEncodeHandler().encode(msg, byteBuffer);
        return byteBuffer.toBytes();
    }
}
